﻿
using MetroFramework.Forms;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using LibGit2Sharp;
using MetroFramework.Controls;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using System.IO.Compression;

namespace BakaGit
{
    static class Program
    {
        public static GitProject info = null;
        public static LibGit2Sharp.Repository repository = null;
        public static bool UseUTC = false;
        public static LibGit2Sharp.Signature me
        {
            get { 
                return new LibGit2Sharp.Signature(info.username, info.email, UseUTC ? DateTimeOffset.UtcNow : DateTimeOffset.Now);
            }
        }
        public static UsernamePasswordCredentials credential;
        public static string configpath = "";
        [STAThread]
        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                var arg0 = args[0];
                if (arg0.ToLower().EndsWith(".bakarepo"))
                {
                    var file = arg0;
                    if (File.Exists(file))
                    {
                        configpath = Path.GetFullPath(file);
                        Environment.CurrentDirectory = Path.GetDirectoryName(file);
                    }
                }
            }
            else
            {

                Environment.CurrentDirectory = Application.StartupPath;
            }


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            InitGitSharpLibrary();
            begin();
        }

        private static void InitGitSharpLibrary()
        {
            byte[] nativeBinariesZip = Properties.Resources.git2native;
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string version = Application.ProductVersion;
            string destinationPath = Path.Combine(appDataPath, "BakaGit", version);

            // 根据操作系统位数选择正确的目录
            string architecture = Environment.Is64BitOperatingSystem ? "x64" : "x86";
            string nativeLibraryPath = Path.Combine(destinationPath, architecture);

            if (!Directory.Exists(nativeLibraryPath))
            {
                // 确保目标目录存在
                Directory.CreateDirectory(destinationPath);

                // 将压缩包内容解压到目标目录
                using (var memoryStream = new MemoryStream(nativeBinariesZip))
                using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
                {

                    // 遍历 ZipArchive 中的每个条目
                    foreach (ZipArchiveEntry entry in archive.Entries)
                    {
                        // 构建完整的文件路径
                        string fullZipToPath = Path.Combine(destinationPath, entry.FullName);

                        // 如果条目是目录，则创建目录
                        if (entry.FullName.EndsWith("/"))
                        {
                            Directory.CreateDirectory(fullZipToPath);
                        }
                        else
                        {
                            // 确保条目的父目录存在
                            Directory.CreateDirectory(Path.GetDirectoryName(fullZipToPath));

                            // 将条目解压到文件系统
                            using (var entryStream = entry.Open())
                            using (var fileStream = new FileStream(fullZipToPath, FileMode.Create, FileAccess.Write))
                            {
                                entryStream.CopyTo(fileStream);
                            }
                        }
                    }
                }
            }
            // 设置LibGit2Sharp的NativeLibraryPath
            GlobalSettings.NativeLibraryPath = nativeLibraryPath;
        }

        public static void begin()
        {
            if(configpath == null)
            {
                configpath = Path.GetFileNameWithoutExtension(Application.ExecutablePath) + ".bakarepo";
            }
            if (File.Exists(configpath))
            {
                info = JsonConvert.DeserializeObject<GitProject>(File.ReadAllText(configpath));
                LibGit2Sharp.RepositoryOptions options = new LibGit2Sharp.RepositoryOptions();
                if (Directory.Exists(Path.Combine(Environment.CurrentDirectory, info.localPath, ".git")))
                {
                    repository = new LibGit2Sharp.Repository(Path.Combine(Environment.CurrentDirectory, info.localPath, ".git"));
                    credential = new UsernamePasswordCredentials() {Username = info.username,Password = info.GetPasswordDecrypted() };
                }
                else
                {
                    if(Directory.Exists(Path.Combine(Environment.CurrentDirectory, info.localPath))){
                        MessageBox.Show("项目目录已存在，但不是一个有效的Git仓库，请检查文件夹");
                        return;
                    }
                    if (MessageBox.Show("仓库目录尚不存在，是否克隆仓库？","克隆项目",MessageBoxButtons.YesNo) != DialogResult.Yes)
                    {
                        return;
                    }
                    try
                    {
                        ConfigForm.CloneProject(info);
                        begin();
                        return;
                    }
                    catch (Exception ex) {
                        MessageBox.Show("克隆发生错误:\r\n"+ex.ToString());
                        return;
                    }

                    
                }
            }
            else
            {
                Application.Run(new ConfigForm());
                if (info != null)
                {
                    File.WriteAllText(configpath, JsonConvert.SerializeObject(info));
                    begin();
                    return;
                }
                else
                {
                    return;
                }
            }
            Application.Run(new Form1());
            repository.Dispose();
            
        }


        public static void setDict<T>(this MetroComboBox cmb, Dictionary<String, T> dict)
        {
            cmb.DataSource = null;
            cmb.Items.Clear();
            cmb.Text = "";
            cmb.Enabled = false;

            if (null != dict && dict.Count > 0)
            {
                cmb.DataSource = new BindingSource() { DataSource = dict };
                cmb.DisplayMember = "Key";
                cmb.ValueMember = "Value";
                cmb.Enabled = true;
            }
        }

    }



    public class BaseForm : MetroForm { 
        public BaseForm() : base(){
            Icon = Properties.Resources.bakagit;
            ShadowType = MetroFormShadowType.AeroShadow;
            Style = MetroFramework.MetroColorStyle.Blue;
        }
        internal void fixWindowTop()
        {
            this.TopMost = true;
            Application.DoEvents();
            this.TopMost = false;
        }
    }


    public class GitProject
    {
        public String repoName;
        public String repoUrl;
        public String localPath;
        public String username;
        public String password;
        public String email;

        private const string aesKey = "8DAA9A5DC3BB4E87874F991EE6BC3D87";
        /// <summary>
        /// Constructor for Newtonsoft.Json
        /// </summary>
        public GitProject()
        {

        }

        public string GetPasswordDecrypted()
        {
            // 确保密钥长度正确
            if (aesKey.Length != 16 && aesKey.Length != 24 && aesKey.Length != 32)
            {
                throw new ArgumentException("AES密钥长度必须是128位、192位或256位");
            }

            // 使用aesKey解密password
            byte[] encryptedBytes = Convert.FromBase64String(password);
            byte[] keyBytes = Encoding.UTF8.GetBytes(aesKey);
            byte[] iv = new byte[16]; // AES的默认初始化向量大小

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = iv;

                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msDecrypt = new MemoryStream(encryptedBytes))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            return srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
        }

        public void SetPasswordEncrypted(string password)
        {
            // 确保密钥长度正确
            if (aesKey.Length != 16 && aesKey.Length != 24 && aesKey.Length != 32)
            {
                throw new ArgumentException("AES密钥长度必须是128位、192位或256位");
            }

            // 使用aesKey加密password
            byte[] keyBytes = Encoding.UTF8.GetBytes(aesKey);
            byte[] iv = new byte[16]; // AES的默认初始化向量大小

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = iv;

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(password);
                        }
                    }
                    this.password = Convert.ToBase64String(msEncrypt.ToArray());
                }
            }
        }

        public GitProject(string repoName, string repoUrl, string localPath, string username, string password,string email)
        {
            this.repoName = repoName;
            this.repoUrl = repoUrl;
            this.localPath = localPath;
            this.username = username;
            SetPasswordEncrypted(password);
            this.email = email;
        }
    }
}
